﻿using System.Collections.Generic;
using System.IO;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Metadata;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.SdkTypeProxy.Metadata;
using System;

namespace CSP.CRM.Deployer
{


  public class CustomizationDeployer
  {
    private CrmService crm;
    private MetadataService meta;
  
    private string[] procedureNames;
    private TextWriter log;
    private string filesDirectory;

    private int languageCode = 1033;
    public int LanguageCode
    {
      get { return languageCode; }
      set { languageCode = value; }
    }

    public CustomizationDeployer(CrmService crm, MetadataService meta, TextWriter log)
    {
      this.crm = crm;
      this.meta = meta;
      this.log = log;
      filesDirectory = Directory.GetCurrentDirectory() + @"\files\";
    }

    public void Run()
    {
      log.WriteLine("Importing customization files...");
      string[] fileNames = Directory.GetFiles(filesDirectory, "csp_customizations_??.xml");
      foreach (string fileName in fileNames)
      {
        log.WriteLine("Importing {0}", fileName);
        ImportCustomizations(fileName);
      }
      log.Write("Synchronizing csp_proceduretype attribute with procedure metadata...");
      SynchronizeProcedureTypeAttribute();
      PublishAllXmlRequest req = new PublishAllXmlRequest();
      crm.Execute(req);
      log.WriteLine("Done");
    }

    private void ImportCustomizations(string fileName)
    {
      try
      {
        ImportAllXmlRequest req = new ImportAllXmlRequest();
        using (StreamReader sr = File.OpenText(fileName))
        {
          req.CustomizationXml = sr.ReadToEnd();
        }
        ImportAllXmlResponse resp = crm.Execute(req) as ImportAllXmlResponse;
      }
      catch (Exception ex)
      {
        log.WriteLine("{0}: {1}", ex.GetType(), ex.Message);
      }
    }

    private void SynchronizeProcedureTypeAttribute()
    {
      foreach (int value in GetProcedureTypeValues())
        DeleteProcedureTypeOption(value);
      Dictionary<string, int> metadataInfo = GetCustomEntitiesInfo();
      foreach (string entity in metadataInfo.Keys)
        InsertProcedureTypeOption(metadataInfo[entity], entity);
    }

    private List<int> GetProcedureTypeValues()
    {
      List<int> values = new List<int>();
      RetrieveEntityRequest req = new RetrieveEntityRequest();
      req.EntityItems = EntityItems.IncludeAttributes;
      req.RetrieveAsIfPublished = true;
      req.LogicalName = "incident";
      RetrieveEntityResponse resp = (RetrieveEntityResponse)meta.Execute(req);
      PicklistAttributeMetadata procedureTypeMetadata = null;
      foreach (AttributeMetadata amd in resp.EntityMetadata.Attributes)
        if (amd.SchemaName == "csp_proceduretype")
        {
          procedureTypeMetadata = (PicklistAttributeMetadata)amd;
          break;
        }
      if (procedureTypeMetadata != null)
        foreach (Option op in procedureTypeMetadata.Options)
          values.Add(op.Value.Value);
      return values;
    }


    private void InsertProcedureTypeOption(int value, string text)
    {
      InsertOptionValueRequest req = new InsertOptionValueRequest();
      LocLabel locLabel = new LocLabel();     
      locLabel.Label = text;
      locLabel.LanguageCode = new CrmNumber();
      locLabel.LanguageCode.Value = languageCode;
      req.Label = new CrmLabel();
      req.Label.LocLabels = new LocLabel[] { locLabel };
      req.Value = new CrmNumber();
      req.Value.Value = value;
      req.AttributeLogicalName = "csp_proceduretype";
      req.EntityLogicalName = "incident";
      InsertOptionValueResponse resp = (InsertOptionValueResponse)meta.Execute(req);
    }

    private void DeleteProcedureTypeOption(int value)
    {
      DeleteOptionValueRequest req = new DeleteOptionValueRequest();
      req.AttributeLogicalName = "csp_proceduretype";
      req.EntityLogicalName = "incident";
      req.Value = value;
      DeleteOptionValueResponse resp = (DeleteOptionValueResponse)meta.Execute(req);
    }

    private Dictionary<string, int> GetCustomEntitiesInfo()
    {
      List<string> procedureNamesList = new List<string>();
      Dictionary<string, int> info = new Dictionary<string, int>();
      RetrieveAllEntitiesRequest req = new RetrieveAllEntitiesRequest();
      req.MetadataItems = MetadataItems.EntitiesOnly;
      RetrieveAllEntitiesResponse resp = (RetrieveAllEntitiesResponse)meta.Execute(req);
      foreach (EntityMetadata emd in resp.CrmMetadata)
      {
        if (!emd.SchemaName.StartsWith("csp_"))
          continue;
        string displayName = emd.DisplayName.UserLocLabel.Label;
        info[displayName] = emd.ObjectTypeCode.Value;
        procedureNamesList.Add(emd.SchemaName);
      }
      procedureNames = procedureNamesList.ToArray();
      return info;
    }

    public string[] GetProcedureNames()
    {
      return procedureNames;
    }

  }
}
